import 'dart:convert';

import 'package:dio/dio.dart' as prefix;
import 'package:record/record.dart';

import '../httputils/http_man.dart';
import '../httputils/urlpath.dart';
import '../util.dart';

class RecordMan {
  final _appid = "d2474055";
  final _sk = "07c06d751aa018042071a461fe84ebcd";

  final record = AudioRecorder();
  final file = FileManager();

  String? _path;
  DateTime? _start;
  DateTime? _end;
  Future<bool> isRecording() {
    return record.isRecording();
  }

  void start() async {
    if (await record.hasPermission()) {
      bool result = await record.hasPermission();
      if (!result) {
        return;
      }
      if (await record.isRecording()) {
        await record.stop();
      }
      _start = DateTime.now();
      var _time = _start!.millisecondsSinceEpoch;
      var _fileName = '${_time}say.m4a';
      _path = await file.tempPath(_fileName);
      await record.start(
        const RecordConfig(),
        path: _path!, // required
      );

      var isRecording = await record.isRecording();
      if (isRecording) {
        Get.log('录制开始');
      } else {
        Get.log('录制失败');
      }
    } else {
      Hud.toast('没有录音权限');
    }
  }

  Future<RecordResult> stop() async {
    var isRecording = await record.isRecording();
    if (!isRecording) {
      _deInit();
      return RecordResult.cancel();
    }
    var path = await record.stop();

    if (path != null) {
      _end = DateTime.now();
      var duration =
          _end!.millisecondsSinceEpoch - _start!.millisecondsSinceEpoch;
      var sections = duration.seconds.inSeconds;
      if (sections == 0) {
        Hud.toast('录制时间太短');
      } else {
        return transform(path,
            duration: duration, fileName: path.split('/').last);
      }
    } else {
      Hud.toast('录制时间太短');
    }
    _deInit();
    return RecordResult.fail();
  }

  Future<RecordResult> cancel() async {
    var isRecording = await record.isRecording();
    if (!isRecording) {
      _deInit();
      return RecordResult.cancel();
    }
    await record.stop();
    return RecordResult.cancel();
  }

  void dispose() {
    record.stop();
    record.dispose();
  }

  void _deInit() {
    _path = null;
    _start = null;
    _end = null;
    file.delPath(_path);
  }

  Future<List?> upload(String path) async {
    var file = prefix.MultipartFile.fromFileSync(path);
    var data = prefix.FormData.fromMap({
      'files': [file]
    });
    var res = await HttpMan.instance.upload(UrlPath.uploadFiles, data: data);
    if (res.isSuccess) {
      return res.data;
    }

    return [];
  }

  Future<String?> xflyUpload(
    String path, {
    required int duration,
    required String fileName,
  }) async {
    var appid = _appid;
    // var appid = "595f23df";
    var sk = _sk;
    // var sk = "d9f4aa7ea6d94faca62cd88a28fd5234";
    var ts = DateTime.now().millisecondsSinceEpoch ~/ 1000;
    // var ts = 1512041814;
    var baseString = appid + ts.toString();
    var md5 = baseString.md5String;
    var sha1 = md5.hmacSHA1(md5, sk);
    var signa = base64Encode(sha1.bytes);
    var fileSize = await file.fileSize(path);
    var url =
        "https://raasr.xfyun.cn/v2/api/upload?duration=$duration&signa=${Uri.encodeComponent(signa)}&fileName=${Uri.encodeComponent(fileName)}&fileSize=$fileSize&sysDicts=uncivilizedLanguage&appId=$appid&ts=$ts";

    var res = await HttpMan.instance
        .stream(url, filePath: path, needBaseResp: false, loadding: false);
    var map = res.data;

    if (map['code'] == "000000") {
      Map content = map['content'];
      var orderId = content['orderId'].toString();
      return xflyResult(orderId, signa: signa, ts: ts);
    } else {
      Hud.toast(map['descInfo'].toString());
    }

    return null;
  }

  Future<String?> xflyResult(
    String orderId, {
    required String signa,
    required int ts,
  }) async {
    var url =
        "https://raasr.xfyun.cn/v2/api/getResult?signa=${Uri.encodeComponent(signa)}&orderId=$orderId&appId=$_appid&resultType=transfer,predict&ts=$ts";

    // var url =
    //     "https://raasr.xfyun.cn/v2/api/getResult?signa=aZUPWVdBUqPEjK7Teq44PnqSsyQ%3D&orderId=DKHJQ20230725153328499guqLe4UnQjKWefUW&appId=d2474055&resultType=transfer,predict&ts=1690270407";
    var res =
        await HttpMan.instance.post(url, needBaseResp: false, loadding: false);
    var map = res.data;
    if (map['code'] == "000000") {
      Map content = map['content'];
      var info = content['orderInfo'];
      var status = info['status'];

      if (status != 4 && status != -1) {
        Hud.show();
        await Future.delayed(const Duration(seconds: 3));
        return xflyResult(orderId, signa: signa, ts: ts);
      }

      Map? result = jsonDecode(content['orderResult']);
      if (result != null) {
        List lattice = result['lattice'];
        var tw = '';
        for (Map data in lattice) {
          var best = jsonDecode(data['json_1best']);
          List ws = best['st']['rt'][0]['ws'];
          var w = ws.map((e) => e['cw'][0]['w']).join('');
          tw += w;
        }
        Get.log('解析结果为：$tw');
        return tw;
      }
    } else {
      Hud.toast(map['descInfo'].toString());
    }
    return null;
  }

  Future<RecordResult> transform(
    String path, {
    required int duration,
    required String fileName,
  }) async {
    Hud.instance.userInteractions = false;
    Hud.show();
    var trans = await xflyUpload(path, duration: duration, fileName: fileName);
    if (trans == null) {
      _deInit();
      Hud.dismiss();
      return RecordResult.fail();
    }
    var sp = await upload(path);
    Hud.dismiss();
    _deInit();
    if (sp != null) {
      return RecordResult.success(
        sp: sp,
        transform: trans,
        duration: duration,
      );
    }
    return RecordResult.fail();
  }
}

class RecordResult {
  late int status;
  List sp = [];
  String transform = '';
  int duration = 0;
  RecordResult({
    required this.status,
    required this.sp,
    required this.transform,
    required this.duration,
  });
  RecordResult.success({
    required this.sp,
    required this.transform,
    required this.duration,
  }) {
    status = 0;
  }
  RecordResult.wait() {
    status = -1;
  }
  RecordResult.cancel() {
    status = 1;
  }
  RecordResult.fail() {
    status = 2;
  }

  String get des {
    return "$sp\n$transform";
  }

  Map<String, dynamic> get json {
    return {
      'status': status,
      'url': sp,
      'trans': transform,
      'duration': duration,
    };
  }

  Map<String, dynamic> get dataJson {
    return sp.isEmpty ? {} : sp.first
      ..['duration'] = (duration / 1000).ceil()
      ..['trans'] = transform;
  }
}
